package com.sz.common.base.logger;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;

import java.net.InetAddress;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Function: AgentAppender <br>
 * Author: Charles <br>
 * Date: 2016-11-30 11:25:00
 */
public class AgentAppender extends AppenderBase<ILoggingEvent> {

    private String agentName;
    protected int bufferSize = 1000;

    protected LinkedBlockingQueue<ILoggingEvent> logsQueue = null;
    protected Thread consumerThread = null;

    protected LogConsumer consumer = null;

    private boolean isConsumerRunning = false;

    /**
     * @param bufferSize --缓存区大小
     */
    public void setBufferSize(int bufferSize) {
        if (bufferSize > 0) {
            this.bufferSize = bufferSize;
        }
    }

    /**
     * @param agentName --Agent Name
     */
    public void setAgentName(String agentName) {
        this.agentName = agentName;
    }

    public String getAgentName() {
        String name = this.agentName;
        if (name == null || name.length() == 0) {
            name = "defaultAgent";
        }
        name += "-" + getIp();
        return name;
    }

    private String getIp() {
        try {
            InetAddress address = InetAddress.getLocalHost();
            return address.getHostAddress();
        } catch (Exception ex) {
            ex.printStackTrace(); //only print exception here, avoid infinite loop
        }
        return "unknown-host";
    }

    @Override
    public void start() {
        super.start();
        logsQueue = new LinkedBlockingQueue<>(this.bufferSize + 10);
        this.consumer = new DbLogConsumer(getAgentName());

        consumerThread = new Thread(() -> consumeLogs(), "logConsumerThread");
        this.isConsumerRunning = true;
        this.consumerThread.start();
    }

    @Override
    public void stop() {
        if (consumerThread != null) {
            this.isConsumerRunning = false;
        }
        super.stop();
    }


    @Override
    protected void append(ILoggingEvent iLoggingEvent) { //add logs to buffer
        if (this.logsQueue.size() < bufferSize) {
            try {
                this.logsQueue.put(iLoggingEvent);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

    private void consumeLogs() {
        while (isConsumerRunning) { // 当前为守护线程
            try {
                ILoggingEvent log = this.logsQueue.take();  // 阻塞
                this.consumer.consumeLog(log);
            } catch (Throwable ex) {
                // DO NOT THROW EXCEPTION HERE
                ex.printStackTrace();
            }
        }
    }
}
